/////////////////////////////////////////////////////////////////////////////
// Name:        epub_property.cpp
// Purpose:     EbProperty objects represent name/value pairs.
// Author:      Julian Smart
// Modified by:
// Created:     2002-12-11
// RCS-ID:      $Id: wbproperty.cpp,v 1.2 2008/01/18 13:11:24 anthemion Exp $
// Copyright:   (c) Julian Smart
// Licence:     New BSD License
/////////////////////////////////////////////////////////////////////////////

#include "wx/wx.h"

#include "epubutils/epub_property.h"

IMPLEMENT_CLASS(EpProperty, wxObject)

IMPLEMENT_CLASS(EpProperties, wxObject)

EpProperty* EpProperties::AddProperty(EpProperty* property, const wxString& insertAfter)
{
    EpProperty* oldProp = FindProperty(property->GetName());
    if (oldProp)
        m_list.DeleteObject(oldProp);

    wxObjectList::compatibility_iterator insertBeforeNode = NULL;
    if (!insertAfter.IsEmpty())
    {
        EpProperty* insertAfterProp = FindProperty(insertAfter);
        if (insertAfterProp)
        {
            wxObjectList::compatibility_iterator node = m_list.Member(insertAfterProp);
            if (node)
                insertBeforeNode = node->GetNext();
        }
    }
    if (insertBeforeNode)
        m_list.Insert(insertBeforeNode, property);
    else
        m_list.Append(property);

    if (oldProp)
    {
        property->GetVariant() = oldProp->GetVariant();

        delete oldProp;
    }
    return property;
}

void EpProperties::RemoveProperty(EpProperty* property)
{
    m_list.DeleteObject(property);
}

void EpProperties::DeleteProperty(EpProperty* property)
{
    m_list.DeleteObject(property);
    delete property;
}

void EpProperties::DeleteProperty(size_t i)
{
    EpProperty* prop = GetProperty(i);
    if (prop)
        DeleteProperty(prop);
}

void EpProperties::DeleteProperty(const wxString& name)
{
    EpProperty* prop = FindProperty(name);
    if (prop)
    {
        m_list.DeleteObject(prop);
        delete prop;
    }
}

EpProperty* EpProperties::FindProperty(const wxString& name) const
{
    wxObjectList::compatibility_iterator node = m_list.GetFirst();
    while (node)
    {
        EpProperty* prop = (EpProperty*) node->GetData();
        if (prop->GetName() == name)
            return prop;

        node = node->GetNext();
    }
    return (EpProperty*) NULL;
}

EpProperty* EpProperties::FindPropertyByDisplayName(const wxString& name)
{
    wxObjectList::compatibility_iterator node = m_list.GetFirst();
    while (node)
    {
        EpProperty* prop = (EpProperty*) node->GetData();
        if (prop->GetDisplayName() == name)
            return prop;

        node = node->GetNext();
    }
    return (EpProperty*) NULL;
}

wxVariant EpProperties::FindPropertyValue(const wxString& name) const
{
    EpProperty* prop = FindProperty(name);
    if (prop)
        return prop->m_variant;
    else
        return wxEmptyString;
}

wxString EpProperties::FindPropertyValueString(const wxString& name) const
{
    EpProperty* prop = FindProperty(name);
    if (prop)
        return prop->m_variant.GetString();
    else
        return wxEmptyString;
}

bool EpProperties::FindPropertyValueBool(const wxString& name) const
{
    EpProperty* prop = FindProperty(name);
    if (prop)
        return prop->m_variant.GetBool();
    else
        return false;
}

long EpProperties::FindPropertyValueLong(const wxString& name) const
{
    EpProperty* prop = FindProperty(name);
    if (prop)
        return prop->m_variant.GetLong();
    else
        return 0;
}

double EpProperties::FindPropertyValueDouble(const wxString& name) const
{
    EpProperty* prop = FindProperty(name);
    if (prop)
        return prop->m_variant.GetDouble();
    else
        return 0.0;
}

EpProperty* EpProperties::FindOrCreateProperty(const wxString& name)
{
    EpProperty* prop = FindProperty(name);
    if (!prop)
    {
        prop = new EpProperty(name);
        AddProperty(prop);
    }
    return prop;
}

void EpProperties::Clear()
{
    m_list.DeleteContents(TRUE);
    m_list.Clear();
    m_list.DeleteContents(FALSE);
}

void EpProperties::Copy(const EpProperties& properties)
{
    wxObjectList::compatibility_iterator node = properties.m_list.GetFirst();
    while (node)
    {
        EpProperty* prop = (EpProperty*) node->GetData();

        AddProperty(new EpProperty(* prop));

        node = node->GetNext();
    }
}

bool EpProperties::operator == (const EpProperties& properties)
{
    if (m_list.GetCount() != properties.m_list.GetCount())
        return false;

    wxObjectList::compatibility_iterator node1 = m_list.GetFirst();
    wxObjectList::compatibility_iterator node2 = properties.m_list.GetFirst();
    while (node1 && node2)
    {
        EpProperty* prop1 = (EpProperty*) node1->GetData();
        EpProperty* prop2 = (EpProperty*) node2->GetData();

        if (!(*prop1 == *prop2))
            return false;

        node1 = node1->GetNext();
        node2 = node2->GetNext();
    }
    return true;
}

void EpProperties::SetProperty(const wxString& name, const wxString& value)
{
    EpProperty* prop = FindOrCreateProperty(name);
    prop->SetValue(value);
}

void EpProperties::SetProperty(const wxString& name, long value)
{
    EpProperty* prop = FindOrCreateProperty(name);
    prop->GetVariant() = value;
}

void EpProperties::SetProperty(const wxString& name, double value)
{
    EpProperty* prop = FindOrCreateProperty(name);
    prop->GetVariant() = value;
}

void EpProperties::SetProperty(const wxString& name, bool value)
{
    EpProperty* prop = FindOrCreateProperty(name);
    prop->GetVariant() = (bool) value;
}

void EpProperties::SetProperty(const wxString& name, const wxVariant& value)
{
    EpProperty* prop = FindOrCreateProperty(name);
    prop->SetValue(value);
}

EpProperty* EpProperties::GetNth(int i) const
{
    wxASSERT( i < (int) GetCount() );
    if (i < (int) GetCount())
    {
        wxObjectList::compatibility_iterator node = m_list.Item(i);
        return (EpProperty*) node->GetData();
    }
    return NULL;
}

/// Combine the styles of all selected properties
/// with this group name.
long EpProperties::CombineStyles(const wxString& groupName, const wxString& WXUNUSED(useVersion))
{
    long styleValue = 0;

    wxObjectList::compatibility_iterator node = m_list.GetFirst();
    while (node)
    {
        EpProperty* prop = (EpProperty*) node->GetData();

        // Assume for now that if we have 2 contradictory styles,
        // we'll filter it out in the appropriate code when checking
        // real version and target version.
        if (prop->GetGroupName() == groupName && prop->GetVariant().GetBool())
        {
            styleValue |= prop->GetStyleValue();
        }

        node = node->GetNext();
    }
    return styleValue;
}

/// Combine the styles of all selected properties
/// with this group name.
wxString EpProperties::CombineStylesString(const wxString& groupName, const wxString& WXUNUSED(useVersion))
{
    wxString styleList;

    wxObjectList::compatibility_iterator node = m_list.GetFirst();
    while (node)
    {
        EpProperty* prop = (EpProperty*) node->GetData();

        if (prop->GetGroupName() == groupName && prop->GetVariant().GetBool())
        {
            if (styleList.IsEmpty())
                styleList = prop->GetName();
            else
                styleList = styleList + _T("|") + prop->GetName();
        }

        node = node->GetNext();
    }
    wxString customStyles = FindPropertyValueString(wxT("Custom styles"));
    if (groupName == wxT("window-style") && !customStyles.IsEmpty())
    {
        if (!styleList.IsEmpty())
            styleList += wxT("|");
        styleList += customStyles;
    }

    return styleList;
}

// Remove any spurious properties that need garbage
// collecting.
void EpProperties::RemoveHiddenProperties()
{
    wxObjectList::compatibility_iterator node = m_list.GetFirst();
    while (node)
    {
        EpProperty* prop = (EpProperty*) node->GetData();
        wxObjectList::compatibility_iterator next = node->GetNext();

        if (!prop->IsShown())
        {
            delete node;
            delete prop;
        }

        node = next;
    }
}
